JAVA POI 实现EXCEL 动态表头、动态添加数据(导入导出)、 Tree结构的遍历

您所在的位置:网站首页 java excel 合并 JAVA POI 实现EXCEL 动态表头、动态添加数据(导入导出)、 Tree结构的遍历

JAVA POI 实现EXCEL 动态表头、动态添加数据(导入导出)、 Tree结构的遍历

2024-06-26 07:47:42| 来源: 网络整理| 查看: 265

前言

GitHub地址:freedom-excel

一、JAVA POI 实现EXCEL 工具类

我们目的是要建立一个EXCEL的工具类,它的功能:

1、可以生成动态表头,单级,多级都支持,尤其是树形表头(整体思路按照树形结构数据来遍历);

2、数据可配置,支持动态填写数据(一个List结构的数据);

3、读取Excel数据;

设计思路:需要一个含有树形结构的实体类Column,用于转换外部数据;而且该实体类要记录下它自己在EXCEL表中的坐标,以及跨行,跨列;接着用这个实体类来生成EXCEL表中的单元格cell。其中还需一个Tree工具类,它要处理Tree型结构数据;最终达到灵活导入导出Excel。

备注: tree根(最顶的节点root)的id必须为零。

二、工具,知识

工具:Java8 + PIO3.9+ Maven +Idea

知识:PIO操作Excel、递归使用、Map List 的遍历、Java类的反射、File的读写

三、代码

 补充:

org.apache.poi poi 3.9 org.apache.poi poi-ooxml 3.9

(1)Column的实体类

/** * Created by wtj on 2018/5/2. */ import java.util.ArrayList; import java.util.List; public class Column { //单元格内容 private String content; //字段名称,用户导出表格时反射调用 private String fieldName; //这个单元格的集合 private List listTpamscolumn = new ArrayList(); int totalRow; int totalCol; int row;//excel第几行 int col;//excel第几列 int rLen; //excel 跨多少行 int cLen;//excel跨多少列 private boolean HasChilren;//是否有子节点 private int tree_step;//树的级别 从0开始 private String id; private String pid; public Column(){}; public Column(String content, String fieldName){ this.content = content; this.fieldName = fieldName; } public Column(String fieldName, String content, int tree_step) { this.tree_step = tree_step; this.fieldName = fieldName; this.content = content; } public int getTotalRow() { return totalRow; } public void setTotalRow(int totalRow) { this.totalRow = totalRow; } public int getTotalCol() { return totalCol; } public void setTotalCol(int totalCol) { this.totalCol = totalCol; } public String getPid() { return pid; } public void setPid(String pid) { this.pid = pid; } public String getId() { return id; } public void setId(String id) { this.id = id; } public boolean isHasChilren() { return HasChilren; } public void setHasChilren(boolean hasChilren) { HasChilren = hasChilren; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getFieldName() { return fieldName; } public void setFieldName(String fieldName) { this.fieldName = fieldName; } public List getListTpamscolumn() { return listTpamscolumn; } public void setListTpamscolumn(List listTpamscolumn) { this.listTpamscolumn = listTpamscolumn; } public int getTree_step() { return tree_step; } public void setTree_step(int tree_step) { this.tree_step = tree_step; } public int getRow() { return row; } public void setRow(int row) { this.row = row; } public int getCol() { return col; } public void setCol(int col) { this.col = col; } public int getrLen() { return rLen; } public void setrLen(int rLen) { this.rLen = rLen; } public int getcLen() { return cLen; } public void setcLen(int cLen) { this.cLen = cLen; } }

(2)TreeTool类

import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * 处理tree结构的数据 工具类 * Created by wtj on 2018/5/20 * 修改时间:2019/03/20 */ public class TreeTool { /** * 传入的id 必须存在list集合里 * 获取某节点的深度 * @param list * @param id 根节点 * @param step * @return */ public static int getTreeStep(List list, String id, int step) { if("".equals(id) || null == id) return step; for (Column cc : list) { if (id.equals(cc.getId())) { int temp = step + 1; return getTreeStep(list, cc.getPid(), temp); } } return step; } /** * 遍历所有数据 获取树最大的深度 * @param list * @return */ public static int getMaxStep(List list){ List nums=new ArrayList(); for(Column cc:list){ nums.add( getTreeStep( list,cc.getId(),0)); } return Collections.max(nums); } /** * 获取最底部子节点的个数 所有叶子节点个数 * @param list * @param did * @return */ public static int getDownChilren(List list, String did){ int sum=0; for(Column cc:list){ if(did.equals(cc.getPid())){ sum++; //判断该节点 是否有子节点 if(hasChild(list,cc)) { sum+= getDownChilren(list, cc.getId())-1; } } } return sum; } /** * 获取父节点 * @param list 所有的list数据,一条一条 * @param did 当前节点id * @return */ public static Column getFCol(List list, String did){ for(Column cc:list) { if (did !=null && did.equals(cc.getId())) { return cc; } if (did ==null && did == cc.getId()) { return cc; } } return new Column(){{setCol(0);setRow(0);}}; } /** * 获取兄弟节点个数 这个必须是有排序的 * @param list 所有的list数据,一条一条 * @param column 当前节点信息 * @return */ public static int getBrotherChilNum(List list, Column column ){ int sum=0; for(Column cc:list){ if(column.getId().equals(cc.getId()))break; if(!column.getPid().equals(cc.getPid()))continue; int temp = getDownChilren(list, cc.getId()); if(temp == 0 || temp == 1) sum++; else sum += temp; } return sum; } /** * 根据某节点的第几层的父节点id * @param list 所有的list数据,一条一条 * @param id 当前节点id * @param step 第几层(深度 从零开始) * @return */ public static String getStepFid(List list, String id, int step){ String f_id = null; for (Column cc : list) { if (id.equals(cc.getId())) { int cstep = getTreeStep( list, cc.getId(), 0); if(step == cstep){ return id; } int fstep = getTreeStep( list, cc.getPid(), 0); if(step == fstep){ f_id = cc.getPid();break; }else { getStepFid( list, cc.getPid(), step); } } } return f_id; } /** * 判断是否有子节点 * @param list 遍历的数据 * @param node 某个节点 * @return */ public static boolean hasChild(List list, Column node) { return getChildList(list, node).size() > 0 ? true : false; } /** * 得到子节点列表 * @param list 遍历的数据 * @param node 某个节点 * @return */ public static List getChildList(List list, Column node) { List nodeList = new ArrayList(); Iterator it = list.iterator(); while (it.hasNext()) { Column n = (Column) it.next(); if (n.getPid()!=null && n.getPid().equals( node.getId())) { nodeList.add(n); } } return nodeList; } /** * 使用递归方法建树 * @param treeNodes * @return */ public static List buildByRecursive(List treeNodes,String rootID) { List trees = new ArrayList(); boolean flag = false; boolean sflag = false; for (Column treeNode : treeNodes) { if ((rootID == null && rootID == treeNode.getId()) ) { flag = true; } if( rootID != null && rootID.equals(treeNode.getId())){ flag = true; } if(flag) { trees.add(findChildren(treeNode, treeNodes)); flag = false; } } if(trees.size() 表头数据:报表的表头 * 行内数据:表头以下的数据 * 功能:动态生成单级,多级Excel表头 * 备注:tree型结构数据的root节点的id必须为零(0) * Created by wtj on 2018/3/2. * 修改: * 2019/03/18 修复生成跨列的bug * 2019/03/20 修复集合存在root的时候,生成不了动态表头 * @param */ public class ExcelTool { private HSSFWorkbook workbook;//excel 对象 private String title; //表格标题 private int colWidth = 20; //单元格宽度 private int rowHeight = 20;//单元格行高度 private HSSFCellStyle styleHead; //表头样式 private HSSFCellStyle styleBody; //主体样式 private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //日期格式化,默认yyyy-MM-dd HH:mm:ss /** * 无参数 初始化 对象 */ public ExcelTool(){ this.title="sheet1"; this.workbook = new HSSFWorkbook(); init(0); } /** * 有参数 初始化 对象 * @param title * @param colWidth * @param rowHeight * @param dateFormat */ public ExcelTool(String title,int colWidth,int rowHeight,String dateFormat){ this.colWidth = colWidth; this.rowHeight = rowHeight; this.title = title; this.workbook = new HSSFWorkbook(); this.sdf = new SimpleDateFormat(dateFormat); init(0); } public ExcelTool(String title,int colWidth,int rowHeight){ this.colWidth = colWidth; this.rowHeight = rowHeight; this.title = title; this.workbook = new HSSFWorkbook(); init(0); } public ExcelTool(String title,int colWidth,int rowHeight,int flag){ this.colWidth = colWidth; this.rowHeight = rowHeight; this.title = title; this.workbook = new HSSFWorkbook(); init(flag); } public ExcelTool(String title){ this.title = title; this.workbook = new HSSFWorkbook(); init(0); } /**ExcelTool 属性 get、set 方法 开始*/ public int getColWidth() { return colWidth; } public void setColWidth(int colWidth) { this.colWidth = colWidth; } public int getRowHeight() { return rowHeight; } public void setRowHeight(int rowHeight) { this.rowHeight = rowHeight; } public HSSFWorkbook getWorkbook() { return this.workbook; } public void setWorkbook(HSSFWorkbook workbook) { this.workbook = workbook; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public HSSFCellStyle getStyleHead() { return styleHead; } public void setStyleHead(HSSFCellStyle styleHead) { this.styleHead = styleHead; } public HSSFCellStyle getStyleBody() { return styleBody; } public void setStyleBody(HSSFCellStyle styleBody) { this.styleBody = styleBody; } /**ExcelTool 属性 get、set 方法 结束*/ //内部统一调用的样式初始化 private void init(int styleFlag){ this.styleHead = this.workbook.createCellStyle(); this.styleHead.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中 this.styleHead.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中 this.styleHead.setRightBorderColor(HSSFColor.BLACK.index); this.styleHead.setBottomBorderColor(HSSFColor.BLACK.index); switch(styleFlag){ case 1: this.styleBody = this.workbook.createCellStyle(); this.styleBody.setAlignment(HSSFCellStyle.ALIGN_LEFT);// 左右居中ALIGN_CENTER this.styleBody.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中 this.styleBody.setRightBorderColor(HSSFColor.BLACK.index); this.styleBody.setBottomBorderColor(HSSFColor.BLACK.index); this.styleBody.setBorderRight((short) 1);// 边框的大小 this.styleBody.setBorderBottom((short) 1);// 边框的大小 break; default: this.styleBody = this.workbook.createCellStyle(); this.styleBody.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中ALIGN_CENTER this.styleBody.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中 this.styleBody.setRightBorderColor(HSSFColor.BLACK.index); this.styleBody.setBottomBorderColor(HSSFColor.BLACK.index); this.styleBody.setBorderRight((short) 1);// 边框的大小 this.styleBody.setBorderBottom((short) 1);// 边框的大小 break; } } /** * 导出表格 无返回 * @param listTpamscolumn 表头数据 * @param datas 行内数据 * @param FilePath 保存路径 * @param flag * @param rowFlag * @throws Exception */ public void exportExcel(List listTpamscolumn, List datas, String FilePath, boolean flag, boolean rowFlag) throws Exception{ splitDataToSheets(datas, listTpamscolumn,flag,rowFlag); save(this.workbook,FilePath); } /** * 返回workbook * @param listTpamscolumn 表头数据 * @param datas 行内数据 * @param flag 是否写入行内数据 * @return * @throws Exception */ public HSSFWorkbook exportWorkbook(List listTpamscolumn, List datas , boolean flag) throws Exception{ splitDataToSheets(datas, listTpamscolumn,flag,false); return this.workbook; } /** * 导出表格 有返回值 * @param listTpamscolumn 表头数据 * @param datas 行内数据 * @param flag 只输出表头数据 * @param rowFlag * @return * @throws Exception */ public InputStream exportExcel(List listTpamscolumn, List datas, boolean flag, boolean rowFlag) throws Exception { splitDataToSheets(datas, listTpamscolumn,flag,rowFlag); return save(this.workbook); } /** * 导出Excel,适用于web导出excel * @param sheet excel * @param data 行内数据 * @param listTpamscolumn 表头数据 * @param flag 只输出表头数据 * @param rowFlag 输出展示数据的结构(表头下面行的数据) * @throws Exception */ private void writeSheet(HSSFSheet sheet, List data, List listTpamscolumn, boolean flag, boolean rowFlag) throws Exception { sheet.setDefaultColumnWidth(colWidth); sheet.setDefaultRowHeightInPoints(rowHeight); sheet = createHead(sheet, listTpamscolumn.get(0).getTotalRow(), listTpamscolumn.get(0).getTotalCol()); createHead(listTpamscolumn,sheet,0); if(flag)//控制是否 bug修复:每次写入行数据时,总是漏第一个条数据 rowIndex 错误 writeSheetContent(listTpamscolumn,data,sheet, listTpamscolumn.get(0).getTotalRow()+1,rowFlag); } /** * 拆分sheet,因为每个sheet不能超过65535,否则会报异常 * @param data 行内数据 * @param listTpamscolumn 表头数据 * @param flag 只输出表头数据 * @param rowFlag 输出展示数据的结构(表头下面行的数据) * @throws Exception */ private void splitDataToSheets(List data, List listTpamscolumn, boolean flag, boolean rowFlag)throws Exception{ int dataCount = data.size(); int maxColumn = 65535; int pieces = dataCount/maxColumn; for(int i = 1; i =temp.size()) return; text=String.valueOf( temp.get(j).get(finame)==null?"": temp.get(j).get(finame)); } HSSFRichTextString richString = new HSSFRichTextString(text); cell.setCellValue(richString); } /** * 把column的columnList整理成一个list 过滤表头的脏数据 * @param list 表头数据 * @param listCol 返回新的list * @return * List */ private void getColumnList(List list, List listCol){ for(int i = 0; i < list.size(); i++){ if(list.get(i).getFieldName() != null){ listCol.add(list.get(i)); } List listChilren = list.get(i).getListTpamscolumn(); if(listChilren.size() > 0){ getColumnList( listChilren, listCol); } } } /** * 保存Excel到InputStream,此方法适合web导出excel * @param workbook * @return */ private InputStream save(HSSFWorkbook workbook) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { workbook.write(bos); InputStream bis = new ByteArrayInputStream(bos.toByteArray()); return bis; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 保存excel到本机指定的路径 * @param workbook * @param filePath * @throws IOException */ private void save(HSSFWorkbook workbook, String filePath){ File file = new File(filePath); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } FileOutputStream fOut = null; try { fOut = new FileOutputStream(file); workbook.write(fOut); fOut.flush(); } catch (Exception e) { e.printStackTrace(); } try {if(null!=fOut) fOut.close();} catch (Exception e1) { } } /** * 创建行 * @param row Excel对应的行 * @param tpamscolumn 当前单元格属性 * @param v * @param j * @return * @throws Exception */ public int createRowVal(HSSFRow row, Column tpamscolumn, T v, int j) throws Exception{ //遍历标题 if(tpamscolumn.getListTpamscolumn() != null && tpamscolumn.getListTpamscolumn().size() > 0){ for(int i = 0; i < tpamscolumn.getListTpamscolumn().size(); i++){ createRowVal(row, tpamscolumn.getListTpamscolumn().get(i),v,j); } }else{ createCol(row, tpamscolumn,v); } return j; } /** * 创建单元格 * @param row Excel对应的行 * @param tpamscolumn 当前单元格对象 * @param v * @throws Exception */ public void createCol(HSSFRow row, Column tpamscolumn, T v) throws Exception{ HSSFCell cell = row.createCell( tpamscolumn.getCol()); //创建单元格 cell.setCellStyle(this.styleBody); //设置单元格样式 final Object[] value = {null}; if(v instanceof Map){ Map m=(Map)v; m.forEach((k, val) -> { if(k.equals(tpamscolumn.getFieldName()) && !tpamscolumn.isHasChilren()){ value[0] =val; } }); }else { Class cls = v.getClass();// 拿到该类 Field[] fields=cls.getDeclaredFields();// 获取实体类的所有属性,返回Field数组 for(int i=0;i= firstRow && row = firstColumn && column = firstRow && row = firstColumn && column


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭